package bd.com.escenic.flexilunch.dao;

/**
 * $URL: http://flexilunch.googlecode.com/svn/trunk/core/src/main/java/bd/com/escenic/flexilunch/dao/EntityDAO.java $
 * $Id: EntityDAO.java 16 2009-06-09 04:07:50Z shihab.uddin@gmail.com $
 * $Date: 2009-06-09 04:07:50 +0000 (Tue, 09 Jun 2009) $
 * $Author: shihab.uddin@gmail.com $
 * $Revision: 16 $
 */

import bd.com.escenic.flexilunch.model.Entity;
import bd.com.escenic.flexilunch.service.Service;
import bd.com.escenic.flexilunch.util.HibernateUtil;
import bd.com.escenic.flexilunch.util.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import java.util.Date;
import java.util.List;

/**
 * $Id: EntityDAO.java 16 2009-06-09 04:07:50Z shihab.uddin@gmail.com $.
 *
 * @author <a href="mailto:shihab.uddin@gmail.com">Shihab Uddin</a>
 * @version $Revision: 16 $
 */
abstract class EntityDAO<T extends Entity> implements Service<T> {

  private static final String ID = "id";
  private static final String NAME = "name";

  protected final Logger mLogger = Logger.getLogger(getClass());

  private final Class mClass;

  EntityDAO(final Class pClass) {
    mClass = pClass;
  }

  public T getEntity(final int pId) {
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<T>() {
        @SuppressWarnings("unchecked")
        public T execute(final Session pSession) {
          Criteria criteria = pSession.createCriteria(mClass);
          criteria.add(Restrictions.eq(ID, pId));
          return (T) criteria.uniqueResult();
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return null;
    }
  }

  public T getEntity(final String pName) {
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<T>() {
        @SuppressWarnings("unchecked")
        public T execute(final Session pSession) {
          Criteria criteria = pSession.createCriteria(mClass);
          criteria.add(Restrictions.eq(NAME, pName));
          return (T) criteria.uniqueResult();
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return null;
    }
  }

  public List<T> getEntities() {
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<List<T>>() {
        @SuppressWarnings("unchecked")
        public List<T> execute(final Session pSession) {
          Criteria criteria = pSession.createCriteria(mClass);
          criteria.addOrder(Order.desc(ID));
          return (List<T>) criteria.list();
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return null;
    }
  }

  public List<Integer> getEntityIds() {
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<List<Integer>>() {
        @SuppressWarnings("unchecked")
        public List<Integer> execute(final Session pSession) {
          Criteria criteria = pSession.createCriteria(mClass);
          criteria.addOrder(Order.desc(ID));
          criteria.setProjection(Projections.property(ID));
          return (List<Integer>) criteria.list();
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return null;
    }
  }

  public boolean createEntity(final T pEntity) {
    Date date = new Date();
    pEntity.setDateCreated(date);
    pEntity.setDateUpdated(date);
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<Boolean>() {
        public Boolean execute(final Session pSession) throws HibernateException {
          pSession.merge(pEntity);
          return true;
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return false;
    }
  }

  public boolean updateEntity(final T pEntity) {
    Date date = new Date();
    pEntity.setDateUpdated(date);
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<Boolean>() {
        public Boolean execute(final Session pSession) throws HibernateException {
          pSession.merge(pEntity);
          return true;
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return false;
    }
  }

  public boolean deleteEntity(final int pId) {
    try {
      return HibernateUtil.execute(new HibernateUtil.Transaction<Boolean>() {
        public Boolean execute(final Session pSession) throws HibernateException {
          Criteria criteria = pSession.createCriteria(mClass);
          criteria.add(Restrictions.eq(ID, pId));
          @SuppressWarnings("unchecked")
          T entity = (T) criteria.uniqueResult();
          pSession.delete(entity);
          return true;
        }
      });
    }
    catch (HibernateException e) {
      mLogger.error(e.getMessage(), e);
      return false;
    }
  }
}
